package com.cjkj.equipment.handler;

import com.alibaba.fastjson.JSONObject;
import com.cjkj.common.utils.DateUtils;
import com.cjkj.common.utils.DecimalUtils;
import com.cjkj.common.utils.StringUtils;
import com.cjkj.equipment.config.AMQP;
import com.cjkj.equipment.domain.EquipmentTJ03MonitorRecords;
import com.cjkj.equipment.domain.EquipmentTj03MonitorRecordsEcg;
import com.cjkj.equipment.domain.EquipmentTj03MonitorRecordsHr;
import com.cjkj.equipment.domain.EquipmentUsageRecords;
import com.cjkj.equipment.domain.dto.DeviceStatusDto;
import com.cjkj.equipment.domain.dto.TJ03DataDto;
import com.cjkj.equipment.mapper.EquipmentTj03MonitorRecordsEcgMapper;
import com.cjkj.equipment.mapper.EquipmentTj03MonitorRecordsHrMapper;
import com.cjkj.equipment.service.AMQPService;
import com.cjkj.equipment.service.IEquipmentMonitorRecordsService;
import com.cjkj.equipment.service.IEquipmentService;
import com.cjkj.equipment.service.IEquipmentUsageRecordsService;
import com.cjkj.equipment.util.AMQPUtil;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.jms.Message;
import javax.jms.MessageListener;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 新版多参数监测仪数据订阅处理类
 */
@Service("tj03Handler")
@Slf4j
public class TJ03Handler implements AMQPService {
    @Resource
    AMQP amqp;
    /** 心电数据帧头 */
    private static final String ECG_HEADER = "FFE0";
    /** 心率数据帧头 */
    private static final String HR_HEADER = "FFF0";
    /** 脱落数据帧头 */
    private static final String TALL_OF_HEADER = "FFAA";
    /**  包结尾 */
    private static final String DATA_END = "DD";
    /** 时间数据占位大小 */
    private static final int DATE_TIME_SIZE = 18;

    private static final Logger deviceLog = LoggerFactory.getLogger("device-log");

    @Resource
    IEquipmentMonitorRecordsService monitorRecordsService;

    @Resource
    private IEquipmentService equipmentService;

    @Resource
    private IEquipmentUsageRecordsService usageRecordsService;

    @Resource
    private EquipmentTj03MonitorRecordsEcgMapper ecgMapper;

    @Resource
    private EquipmentTj03MonitorRecordsHrMapper hrMapper;

    private final static ExecutorService executorService = new ThreadPoolExecutor(
            Runtime.getRuntime().availableProcessors(),
            Runtime.getRuntime().availableProcessors() * 2, 60, TimeUnit.SECONDS,
            new LinkedBlockingQueue(50000));

    /**
     * 消费组监听类，有多个消费队列时，根据不同处理方式创建多个消费监听类
     */
    private final MessageListener messageListener = new MessageListener() {
        @Override
        public void onMessage(final Message message) {
            try {
                //1.收到消息之后一定要ACK。
                // 推荐做法：创建Session选择Session.AUTO_ACKNOWLEDGE，这里会自动ACK。
                // 其他做法：创建Session选择Session.CLIENT_ACKNOWLEDGE，这里一定要调message.acknowledge()来ACK。
                // message.acknowledge();
                //2.建议异步处理收到的消息，确保onMessage函数里没有耗时逻辑。
                // 如果业务处理耗时过程过长阻塞住线程，可能会影响SDK收到消息后的正常回调。
                executorService.submit(new Runnable() {
                    @Override
                    public void run() {
                        processMessage(message);
                    }
                });
            } catch (Exception e) {
                log.error("submit task occurs exception ", e);
            }
        }
    };

    @Override
    public void initAmqp() {
        try {
            AMQPUtil.init(amqp.getTj03GroupId(), amqp, messageListener);
        }catch (Exception e){
            log.error("初始化连接失败：",e);
        }
    }

    @Override
    public void processMessage(Message message) {
        byte[] body;
        try {
            body = message.getBody(byte[].class);
        } catch (Exception e){
            log.error("processMessage occurs error ", e);
            throw new RuntimeException("数据采集失败：" + e);
        }
        String content = new String(body);
        log.info("===================TJ03Handler============");
        log.info(content);
        log.info("===================TJ03Handler============");
        TJ03DataDto dto = JSONObject.parseObject(content, TJ03DataDto.class);
        DeviceStatusDto statusDto = JSONObject.parseObject(content, DeviceStatusDto.class);

        // 正在使用的设备才保存数据
        String deviceName = dto.getDeviceName();
        EquipmentUsageRecords inUse = usageRecordsService.getInUseByEquipmentNo(deviceName);
        if(inUse == null) {
            return ;
        }

        // 设备状态
        if(StringUtils.isNotBlank(statusDto.getStatus())){
            //更新设备状态
            boolean update = equipmentService.updateEquipmentStatus(statusDto);
            if(update){
                log.info("更新设备状态成功！{}", statusDto.getDeviceName());
            } else {
                log.error("更新设备状态失败！{}", statusDto.getDeviceName());
            }
            return ;
        }

        if(dto.getItems() == null){
            log.error("接收到的消息为空！");
            return ;
        }

        // 添加监测记录
        EquipmentTJ03MonitorRecords record = getRecordFromDto(dto);
        int insert = monitorRecordsService.insertTJ03MonitorRecords(record);
        if(insert < 1){
            log.error("添加监测记录失败：{}", record);
            return;
        }

        statusDto = new DeviceStatusDto();
        statusDto.setDeviceName(record.getEquipmentNo());
        statusDto.setStatus("online");
        statusDto.setTime(record.getCreateTime());
        //更新设备在线状态
        boolean update = equipmentService.updateEquipmentStatus(statusDto);
        if(update){
            log.info("更新设备状态成功！设备名称：{}，时间：{}", statusDto.getDeviceName(), statusDto);
        }else {
            log.error("更新手环状态失败，设备名称：{}，时间：{}", statusDto.getDeviceName(), statusDto);
        }

        // 解析心电、心率，并保存至数据库
        saveECGData(record);
    }

    private EquipmentTJ03MonitorRecords getRecordFromDto(TJ03DataDto tj03DataDto){
        EquipmentTJ03MonitorRecords record = new EquipmentTJ03MonitorRecords();
        record.setProductId(tj03DataDto.getProductKey());
        record.setEquipmentNo(tj03DataDto.getDeviceName());

        if(tj03DataDto.getItems().getBatpt() != null){
            record.setBatpt(Integer.parseInt(tj03DataDto.getItems().getBatpt().getValue()));
            record.setCreateTime(tj03DataDto.getItems().getBatpt().getTime());
        }
        if(tj03DataDto.getItems().getWState() != null){
            record.setWState(Integer.parseInt(tj03DataDto.getItems().getWState().getValue()));
            record.setCreateTime(tj03DataDto.getItems().getWState().getTime());
        }
        if(tj03DataDto.getItems().getFailState() != null){
            record.setRestHeart(Integer.parseInt(tj03DataDto.getItems().getFailState().getValue()));
            record.setCreateTime(tj03DataDto.getItems().getFailState().getTime());
        }
        if(tj03DataDto.getItems().getBPTRslt() != null){
            record.setBptResult(Integer.parseInt(tj03DataDto.getItems().getBPTRslt().getValue()));
            record.setCreateTime(tj03DataDto.getItems().getBPTRslt().getTime());
        }
        if(tj03DataDto.getItems().getBPTS() != null){
            record.setBptStatus(Integer.parseInt(tj03DataDto.getItems().getBPTS().getValue()));
            record.setCreateTime(tj03DataDto.getItems().getBPTS().getTime());
        }
        if(tj03DataDto.getItems().getPValue() != null){
            record.setPValue(Long.parseLong(tj03DataDto.getItems().getPValue().getValue()));
            record.setCreateTime(tj03DataDto.getItems().getPValue().getTime());
        }
        if(tj03DataDto.getItems().getBPSy() != null){
            record.setSbp(Integer.parseInt(tj03DataDto.getItems().getBPSy().getValue()));
            record.setCreateTime(tj03DataDto.getItems().getBPSy().getTime());
        }
        if(tj03DataDto.getItems().getBPDi() != null){
            record.setDbp(Integer.parseInt(tj03DataDto.getItems().getBPDi().getValue()));
            record.setCreateTime(tj03DataDto.getItems().getBPDi().getTime());
        }
        if(tj03DataDto.getItems().getBPTTRslt() != null){
            record.setBpttResult(Integer.parseInt(tj03DataDto.getItems().getBPTTRslt().getValue()));
            record.setCreateTime(tj03DataDto.getItems().getBPTTRslt().getTime());
        }
        if(tj03DataDto.getItems().getBPTTS() != null){
            record.setBpttStatus(Integer.parseInt(tj03DataDto.getItems().getBPTTS().getValue()));
            record.setCreateTime(tj03DataDto.getItems().getBPTTS().getTime());
        }
        if(tj03DataDto.getItems().getInflDur() != null){
            record.setInflDur(Long.parseLong(tj03DataDto.getItems().getInflDur().getValue()));
            record.setCreateTime(tj03DataDto.getItems().getInflDur().getTime());
        }
        if(tj03DataDto.getItems().getEcgDat() != null){
            record.setEcgData(tj03DataDto.getItems().getEcgDat().getValue());
            record.setCreateTime(tj03DataDto.getItems().getEcgDat().getTime());
        }
        if(tj03DataDto.getItems().getEcgPatchStatus() != null){
            record.setEcgPatchStatus(Integer.parseInt(tj03DataDto.getItems().getEcgPatchStatus().getValue()));
            record.setCreateTime(tj03DataDto.getItems().getEcgPatchStatus().getTime());
        }
        if(tj03DataDto.getItems().getEcgSeq() != null){
            record.setEcgSeq(tj03DataDto.getItems().getEcgSeq().getValue());
            record.setCreateTime(tj03DataDto.getItems().getEcgSeq().getTime());
        }
        if(tj03DataDto.getItems().getEcgPatchPlginSta() != null){
            record.setEcgPatchPlginStatus(Integer.parseInt(tj03DataDto.getItems().getEcgPatchPlginSta().getValue()));
            record.setCreateTime(tj03DataDto.getItems().getEcgPatchPlginSta().getTime());
        }
        if(tj03DataDto.getItems().getPowerStatus() != null){
            record.setPowerStatus(Integer.parseInt(tj03DataDto.getItems().getPowerStatus().getValue()));
            record.setCreateTime(tj03DataDto.getItems().getPowerStatus().getTime());
        }

        return record;
    }

    /**
     * 保存心电数据
     */
    private void saveECGData(EquipmentTJ03MonitorRecords record){
        // 解密心电数据
        String hex = "";
        String base64Str = record.getEcgData();
        if(StringUtils.isNotBlank(base64Str)) {
            hex = StringUtils.base64ToHex(base64Str);
            hex = hex.toUpperCase();
            hex = hex.substring(0, hex.lastIndexOf(DATA_END) + DATA_END.length());
        }
        // 打印信息到日志
        deviceLog.info("RecordId：{}，EquipmentNo：{}，DateTime：{}，EcgData：{}", record.getId(), record.getEquipmentNo(), DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, record.getCreateTime()), hex);

        if(StringUtils.isBlank(hex)) {
            return ;
        }
        List<String> ecgData = new ArrayList<>();
        List<String> hrData = new ArrayList<>();
        List<String> tallOfData = new ArrayList<>();
        do {
            if(hex.length() < 22) {
                break ;
            }
            // 数据帧头
            String dataHead = hex.substring(DATE_TIME_SIZE, 22);
            String dataStr = "";
            if (ECG_HEADER.equals(dataHead)) {
                // 数据长度
                String dataNums = hex.substring(22, 24);
                int decimalNumber = DecimalUtils.getDecimalNumber(dataNums);
                dataStr = hex.substring(0, decimalNumber * 2 + 24 + DATA_END.length());
                ecgData.add(dataStr);
            }
            if (HR_HEADER.equals(dataHead)) {
                // 数据长度
                String dataNums = hex.substring(22, 24);
                int decimalNumber = DecimalUtils.getDecimalNumber(dataNums);
                dataStr = hex.substring(0, decimalNumber * 2 + 24 + DATA_END.length());
                hrData.add(dataStr);
            }
            if (TALL_OF_HEADER.equals(dataHead)) {
                dataStr = hex.substring(0, DATE_TIME_SIZE + dataHead.length() + DATA_END.length());
                tallOfData.add(dataStr);
            }

            hex = hex.substring((StringUtils.isNotBlank(dataStr) ? dataStr : dataHead).length());

        } while (!hex.isEmpty());

        // 添加心电数据
        for (String s : ecgData) {
            Date hexTime = DateUtils.getHexTime(s);
            String data = s.substring(24, s.lastIndexOf(DATA_END));

            List<Integer> ecgNumberList = new ArrayList<>();
            do {
                if (data.length() < 4) {
                    break;
                }
                String ecgHex = data.substring(0, 4);
                ecgNumberList.add(DecimalUtils.int16HexToDecimal(ecgHex));
                data = data.substring(4);
            } while (!data.isEmpty());
            String collect = ecgNumberList.stream().map(String::valueOf).collect(Collectors.joining(","));

            EquipmentTj03MonitorRecordsEcg ecgEntity = new EquipmentTj03MonitorRecordsEcg();
            ecgEntity.setRecordId(record.getId());
            ecgEntity.setEquipmentNo(record.getEquipmentNo());
            ecgEntity.setCreateTime(hexTime);
            ecgEntity.setEcgData(collect);
            ecgMapper.insertEquipmentTj03MonitorRecordsEcg(ecgEntity);
        }

        // 添加心率数据
        for (String s : hrData) {
            Date hexTime = DateUtils.getHexTime(s);
            String data = s.substring(24, s.lastIndexOf(DATA_END));
            int hr = DecimalUtils.hexToDecimal(data);

            EquipmentTj03MonitorRecordsHr hrEntity = new EquipmentTj03MonitorRecordsHr();
            hrEntity.setRecordId(record.getId());
            hrEntity.setEquipmentNo(record.getEquipmentNo());
            hrEntity.setCreateTime(hexTime);
            hrEntity.setHr(hr);
            hrMapper.insertEquipmentTj03MonitorRecordsHr(hrEntity);

            record.setHr(hr);
        }
    }
}